#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
#include "json/json.h"
#include "qbot/qbot.hpp"

typedef websocketpp::server<websocketpp::config::asio> server;

using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;

// pull out the type of messages sent by our config
typedef server::message_ptr message_ptr;

// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
    
#ifdef DEBUG_MSG
    std::cout << "on_message called with hdl: " << hdl.lock().get()
              << " and message: " << msg->get_payload()
              << std::endl;
#endif

    Json::Value root;
    JSONCPP_STRING err;
    Json::CharReaderBuilder build;
    const std::unique_ptr<Json::CharReader> reader(build.newCharReader());

    // check for a special command to instruct the server to stop listening so
    // it can be cleanly exited.
    if (msg->get_payload() == "stop-listening")
    {
        s->stop_listening();
        return;
    }

    if(!reader->parse(
        msg->get_payload().data(), 
        msg->get_payload().data()+msg->get_payload().length(), 
        &root, 
        &err)){
            std::cout << err << std::endl;
    }
    else
    {
        Qbot::parser.parse(root);
        try
        {
            s->send(hdl, Qbot::parser.get_retcode(), msg->get_opcode());
        }
        catch (websocketpp::exception const &e)
        {
            std::cout << "Echo failed because: "
                        << "(" << e.what() << ")" << std::endl;
        }
    }
}

int main(void) {
    // Create a server endpoint
    server qbot_server;
    std::cout << "WebSocekt Server Start." << std::endl;

    if(Qbot::qbot.init())
        std::cout << "Qbot usb port Start." << std::endl;
    else
    {
        std::cerr << "Qbot usb port error!" << std::endl;
        return -1;
    }
    

    try {
        // Set logging settings
        qbot_server.set_access_channels(websocketpp::log::alevel::none);
        // qbot_server.clear_access_channels(websocketpp::log::alevel::frame_payload);

        // Initialize Asio
        qbot_server.init_asio();

        // Initialize Battery Read
        Qbot::battery_init();

        // Register our message handler
        qbot_server.set_message_handler(bind(&on_message,&qbot_server,::_1,::_2));

        //For asio listen error: system:98
        qbot_server.set_reuse_addr(true);

        // Listen on port 19002
        qbot_server.listen(19002);

        // Start the server accept loop
        qbot_server.start_accept();

        // Start the ASIO io_service run loop
        qbot_server.run();
    } catch (websocketpp::exception const & e) {
        std::cout << e.what() << std::endl;
    } catch (...) {
        std::cout << "other exception" << std::endl;
    }

    qbot_server.stop();
    std::cout << "server exit." << std::endl;
    return 0;

}
